﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
using Autodesk.Revit.UI.Selection;
using YArchitech.Controls;
using YArchitech.Revit;
using YJKArchUtils.Utils;
using YJKRevitBase.WinForm;
using YJKRevitParapet.Analyzer;
using YJKRevitParapet.Forms;

namespace YJKRevitParapet.Controller
{
	public class CreateParapetController
	{
		public CreateParapetController(ExternalCommandData cmdData)
		{
			this.m_ComdData = cmdData;
			this.m_Doc = cmdData.Application.ActiveUIDocument.Document;
		}

		public Result AutoCreateParapets()
		{
			ParapetForm parapetForm = new ParapetForm(ParapetForm.FormStyle.FS_CREATE, this.m_ComdData);
			if (parapetForm.ShowDialog() != DialogResult.OK)
			{
				return Autodesk.Revit.UI.Result.Cancelled;
			}
			ParapetForm.ParapetData parapetData = parapetForm.GetParapetData();
			ParapetAnalyzer parapetAnalyzer = new ParapetAnalyzer(this.m_ComdData);
			List<Pole2D> analyzedPolelist = new List<Pole2D>();
			Result parapetBaseline = parapetAnalyzer.GetParapetBaseline(parapetData.Thickness, ref analyzedPolelist);
			if (parapetBaseline != null)
			{
				return parapetBaseline;
			}
			return this.CreateParapets(analyzedPolelist, parapetData, false);
		}

		public Result ManualCreateParapets()
		{
			List<BaseLineController.BaseLineSegmentInfo> baseLineSegmentList = new List<BaseLineController.BaseLineSegmentInfo>();
			ParapetForm parapetForm = new ParapetForm(ParapetForm.FormStyle.FS_EDITBASELINE, this.m_ComdData);
			while (parapetForm.ShowDialog() == DialogResult.OK)
			{
				if (parapetForm.ResultStyle != ParapetForm.FormResultStyle.FRS_BASELINE)
				{
					ParapetForm.ParapetData parapetData = parapetForm.GetParapetData();
					List<Pole2D> analyzedPolelist = new List<Pole2D>();
					this.GetBaseLines(baseLineSegmentList, parapetData.Thickness, ref analyzedPolelist);
					this.CreateParapets(analyzedPolelist, parapetData, false);
					return Autodesk.Revit.UI.Result.Succeeded;
				}
				this.ManualCreateBaseLines(ref baseLineSegmentList);
			}
			this.DeleteBaseLines(baseLineSegmentList);
			return Autodesk.Revit.UI.Result.Cancelled;
		}

		public Result EditParapets()
		{
			List<Wall> list = new List<Wall>();
			ParapetForm parapetForm = new ParapetForm(ParapetForm.FormStyle.FS_EDITWALL, this.m_ComdData);
			while (parapetForm.ShowDialog() == DialogResult.OK)
			{
				if (parapetForm.ResultStyle == ParapetForm.FormResultStyle.FRS_WALL)
				{
					this.SelectParapets(ref list);
					if (list.Count > 0)
					{
						ParapetForm.ParapetData parapetData = new ParapetForm.ParapetData();
						ExtensibleStorageManager.ReadParapetExtensibleStorage(list[0], ref parapetData);
						parapetForm.SetParapetData(parapetData);
						parapetForm.SaveData();
					}
				}
				else
				{
					if (list.Count == 0)
					{
						YJKMessageBox.Show("未选中女儿墙");
						return Autodesk.Revit.UI.Result.Succeeded;
					}
					ParapetForm.ParapetData parapetData2 = parapetForm.GetParapetData();
					List<Pole2D> analyzedPolelist = new List<Pole2D>();
					this.GetBaseLines(list, parapetData2.Thickness, ref analyzedPolelist);
					this.CreateParapets(analyzedPolelist, parapetData2, true);
					return Autodesk.Revit.UI.Result.Succeeded;
				}
			}
			return Autodesk.Revit.UI.Result.Cancelled;
		}

		private Result ManualCreateBaseLines(ref List<BaseLineController.BaseLineSegmentInfo> baseLineSegmentList)
		{
			BaseLineController baseLineController = new BaseLineController(this.m_ComdData, baseLineSegmentList);
			string text = "";
			return baseLineController.EditBaseLine(ref baseLineSegmentList, ref text);
		}

		private Result SelectParapets(ref List<Wall> wallList)
		{
			try
			{
				List<Wall> collection = new List<Wall>();
				if (this.PickParapets(ref collection))
				{
					wallList.AddRange(collection);
					return Autodesk.Revit.UI.Result.Succeeded;
				}
			}
			catch (Exception)
			{
				return Autodesk.Revit.UI.Result.Failed;
			}
			return Autodesk.Revit.UI.Result.Cancelled;
		}

		private bool PickParapets(ref List<Wall> wallList)
		{
			new List<Reference>();
			Selection selection = this.m_ComdData.Application.ActiveUIDocument.Selection;
			try
			{
				ParapetFilter parapetFilter = new ParapetFilter();
				foreach (Reference reference in selection.PickObjects((Autodesk.Revit.UI.Selection.ObjectType)1, parapetFilter, "拾取编辑的女儿墙"))
				{
					Wall item = this.m_Doc.GetElement(reference) as Wall;
					wallList.Add(item);
				}
			}
			catch (Exception)
			{
				return false;
			}
			return true;
		}

		private WallType CreateUserParapetWallType(string typeName, double thickness, double height, bool hasCoping, string strCopingStyleName)
		{
			WallType wallType = this.InitWallTypeByName(typeName);
			CompoundStructure compoundStructure = CreateParapetController.CreateCompoundStructure(thickness, height);
			if (hasCoping)
			{
				double num = thickness / 2.0;
				WallSweepInfo wallSweepInfo = new WallSweepInfo(true, 0);
				this.SetWallSweepInfo(wallSweepInfo, 0.0, -num);
				FamilySymbol userProfile = this.GetUserProfile(thickness, strCopingStyleName);
				if (userProfile != null)
				{
					wallSweepInfo.ProfileId = userProfile.Id;
					wallSweepInfo.Id = 101;
					compoundStructure.AddWallSweep(wallSweepInfo);
				}
			}
			wallType.SetCompoundStructure(compoundStructure);
			return wallType;
		}

		private WallType CreateParapetWallType(string typeName, double thickness, double height, bool hasCoping, int copingStyleIndex)
		{
			WallType wallType = this.InitWallTypeByName(typeName);
			double num = thickness / 2.0;
			CompoundStructure compoundStructure = CreateParapetController.CreateCompoundStructure(thickness, height);
			if (hasCoping)
			{
				WallSweepInfo wallSweepInfo = new WallSweepInfo(true, 0);
				this.SetWallSweepInfo(wallSweepInfo, 0.0, -num);
				FamilySymbol profile = this.GetProfile(thickness, copingStyleIndex);
				if (profile != null)
				{
					wallSweepInfo.ProfileId = profile.Id;
					wallSweepInfo.Id = 101;
					compoundStructure.AddWallSweep(wallSweepInfo);
				}
			}
			wallType.SetCompoundStructure(compoundStructure);
			return wallType;
		}

		private static CompoundStructure CreateCompoundStructure(double thickness, double height)
		{
            MaterialFunctionAssignment materialFunctionAssignment = (MaterialFunctionAssignment)1;
			ElementId invalidElementId = ElementId.InvalidElementId;
			return CompoundStructure.CreateSingleLayerCompoundStructure(height, materialFunctionAssignment, thickness, invalidElementId);
		}

		private WallType InitWallTypeByName(string typeName)
		{
			string text = typeName;
			WallType wallType = null;
			WallType wallType2 = null;
			text = text.Trim();
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfClass(typeof(WallType)).ToElements())
			{
				WallType wallType3 = element as WallType;
				if (wallType3.Name.CompareTo(text) == 0)
				{
					wallType2 = wallType3;
					break;
				}
				if (wallType == null && wallType3.Kind == null)
				{
					wallType = wallType3;
				}
			}
			if (wallType2 == null)
			{
				wallType2 = (wallType.Duplicate(text) as WallType);
			}
			return wallType2;
		}

		private void SetWallSweepInfo(WallSweepInfo wallSweepInfo, double hOffset, double vOffset)
		{
            wallSweepInfo.DistanceMeasuredFrom = (DistanceMeasuredFrom)1;
			wallSweepInfo.Distance = hOffset;
			wallSweepInfo.WallSide = 0;
			wallSweepInfo.Id = -1;
			wallSweepInfo.WallOffset = vOffset;
		}

		private FamilySymbol GetUserProfile(double thickness, string strCopingStyleName)
		{
			AssistFunc.feetToMM(thickness).ToString("f0");
			FamilySymbol familySymbol = (from FamilySymbol e in new FilteredElementCollector(this.m_Doc).OfClass(typeof(FamilySymbol)).OfCategory(BuiltInCategory.OST_ProfileFamilies)
			where e.Family.Name == strCopingStyleName
			select e).Distinct<FamilySymbol>().FirstOrDefault<FamilySymbol>();
			if (familySymbol == null)
			{
				familySymbol = this.LoadUserProfileFamily(strCopingStyleName);
			}
			return familySymbol;
		}

		private FamilySymbol GetProfile(double thickness, int copingStyleIndex)
		{
			string str = AssistFunc.feetToMM(thickness).ToString("f0");
			string str2 = (copingStyleIndex + 1).ToString("f0");
			string text = "HY压顶-" + str + "-" + str2;
			FamilySymbol familySymbol = null;
			foreach (Element element in new FilteredElementCollector(this.m_Doc).OfCategory(BuiltInCategory.OST_ProfileFamilies).ToElements())
			{
				FamilySymbol familySymbol2 = element as FamilySymbol;
				if (familySymbol2.Name.CompareTo(text) == 0)
				{
					return familySymbol2;
				}
				if (familySymbol == null && familySymbol2.Family.Name.IndexOf("HY压顶") != -1)
				{
					familySymbol = familySymbol2;
				}
			}
			if (familySymbol == null && !this.LoadProfileFamily(ref familySymbol))
			{
				return null;
			}
			double num = AssistFunc.mmToFeet(100.0);
			double num2 = AssistFunc.mmToFeet(80.0);
			double num3 = AssistFunc.mmToFeet(60.0);
			double num4 = thickness / 2.0;
			FamilySymbol familySymbol3 = familySymbol.Duplicate(text) as FamilySymbol;
			if (copingStyleIndex == 0)
			{
				familySymbol3.GetParameter("H1").Set(num);
				familySymbol3.GetParameter("H2").Set(num);
				familySymbol3.GetParameter("W1").Set(num4);
				familySymbol3.GetParameter("W2").Set(num4);
			}
			else if (copingStyleIndex == 1)
			{
				familySymbol3.GetParameter("H1").Set(num2);
				familySymbol3.GetParameter("H2").Set(num);
				familySymbol3.GetParameter("W1").Set(num4 + num3);
				familySymbol3.GetParameter("W2").Set(num4 + num3);
			}
			else if (copingStyleIndex == 2)
			{
				familySymbol3.GetParameter("H1").Set(num2);
				familySymbol3.GetParameter("H2").Set(num);
				familySymbol3.GetParameter("W1").Set(num4);
				familySymbol3.GetParameter("W2").Set(num4);
			}
			else
			{
				familySymbol3.GetParameter("H1").Set(num2);
				familySymbol3.GetParameter("H2").Set(num);
				familySymbol3.GetParameter("W1").Set(num4);
				familySymbol3.GetParameter("W2").Set(num4 + num3);
			}
			return familySymbol3;
		}

		private FamilySymbol LoadUserProfileFamily(string strFamilyName)
		{
			string text = ParapetForm.InitUserParapetFilePathWithVersion() + "\\" + strFamilyName + ".rfa";
			Document document = this.m_ComdData.Application.ActiveUIDocument.Document;
			Family family = null;
			if (document.LoadFamily(text, out family))
			{
				return family.GetSymbols().FirstOrDefault<FamilySymbol>();
			}
			return null;
		}

		private bool LoadProfileFamily(ref FamilySymbol profile)
		{
			string versionNumber = this.m_ComdData.Application.Application.VersionNumber;
			string text = this.GetAppRootPath();
			text = text + "\\Templates\\" + versionNumber + "\\HY压顶.rfa";
			if (!File.Exists(text))
			{
				throw new Exception("Unsupported version");
			}
			Family family = null;
            if (this.m_Doc.LoadFamily(text, out family))
			{
				profile = family.GetSymbols().FirstOrDefault<FamilySymbol>();
				return true;
			}
			return false;
		}

		private string GetAppRootPath()
		{
			string location = Assembly.GetExecutingAssembly().Location;
			int length = location.LastIndexOf("\\");
			string text = location.Substring(0, length);
			length = text.LastIndexOf("\\");
			return text.Substring(0, length);
		}

		private void DeleteBaseLines(List<BaseLineController.BaseLineSegmentInfo> baseLineSegmentList)
		{
			List<ElementId> list = new List<ElementId>();
			foreach (BaseLineController.BaseLineSegmentInfo baseLineSegmentInfo in baseLineSegmentList)
			{
				list.Add(baseLineSegmentInfo.BaseLineId);
				list.AddRange(baseLineSegmentInfo.ArrowLineIds);
			}
			BaseLineController.DeleteElements(this.m_Doc, list);
		}

		private bool GetBaseLines(List<BaseLineController.BaseLineSegmentInfo> baseLineSegmentList, double thickness, ref List<Pole2D> analyzedPolelist)
		{
			double num = thickness / 2.0;
			double elevation = this.m_Doc.ActiveView.GenLevel.Elevation;
			List<ElementId> list = new List<ElementId>();
			List<Pole2D> list2 = new List<Pole2D>();
			foreach (BaseLineController.BaseLineSegmentInfo baseLineSegmentInfo in baseLineSegmentList)
			{
				Curve curve = null;
				try
				{
					curve = (this.m_Doc.GetElement(baseLineSegmentInfo.BaseLineId) as DetailCurve).GeometryCurve;
				}
				catch (Exception)
				{
					continue;
				}
				Pole2D item = Pole2D.TransformWallToStructure2DPole(curve, ElementId.InvalidElementId, elevation, num, num);
				list2.Add(item);
				list.Add(baseLineSegmentInfo.BaseLineId);
				list.AddRange(baseLineSegmentInfo.ArrowLineIds);
			}
			BaseLineController.DeleteElements(this.m_Doc, list);
			TopPoleAnalyzer topPoleAnalyzer = new TopPoleAnalyzer(this.m_ComdData);
			List<Pole2D> list3 = new List<Pole2D>();
			if (!topPoleAnalyzer.MergeEdge(list2, ref list3))
			{
				return false;
			}
			new TopPoleAnalyzer(this.m_ComdData).FormatDoubleLine(ref list3);
			new List<Pole2D>();
			foreach (Pole2D pole2D in list3)
			{
				Pole2D item2 = Pole2D.TransformWallToStructure2DPole(pole2D.PositiveCurve(), pole2D.ComponentId, pole2D.Elevation, num, num);
				analyzedPolelist.Add(item2);
			}
			return true;
		}

		private bool GetBaseLines(List<Wall> parapetList, double thickness, ref List<Pole2D> analyzedPolelist)
		{
			double num = thickness / 2.0;
			new List<ElementId>();
			new List<Pole2D>();
			foreach (Wall wall in parapetList)
			{
				Curve curve = (wall.Location as LocationCurve).Curve;
				double num2 = (thickness - wall.Width) / 2.0;
				double elevation = 0.0;
				double num3 = 0.0;
				ParapetAnalyzer.GetWallElevations(this.m_Doc, wall, ref elevation, ref num3);
				Pole2D pole2D = Pole2D.TransformWallToStructure2DPole(curve, wall.Id, elevation, num2, num2);
				Curve curve2;
				if (pole2D.IsArcPole)
				{
					curve2 = pole2D.ReversePositiveCurve();
					XYZ pt = (pole2D.Center - pole2D.StartPoint).Normalize();
					XYZ pt2 = (pole2D.Center - pole2D.EndPoint).Normalize();
					if (Geometry.IsEqual(wall.Orientation, pt) || Geometry.IsEqual(wall.Orientation, pt2))
					{
						curve2 = pole2D.ReverseNegativeCurve();
					}
				}
				else
				{
					curve2 = pole2D.ReversePositiveCurve();
					XYZ xyz = (curve.GetEndPoint(1) - curve.GetEndPoint(0)).Normalize();
					xyz = Geometry.RotateTo(xyz, Math.PI*.5, XYZ.BasisZ);
					if (Geometry.IsEqual(wall.Orientation, xyz))
					{
						curve2 = pole2D.ReverseNegativeCurve();
					}
				}
				Pole2D item = Pole2D.TransformWallToStructure2DPole(curve2, pole2D.ComponentId, pole2D.Elevation, num, num);
				analyzedPolelist.Add(item);
			}
			return true;
		}

		private Result CreateParapets(List<Pole2D> analyzedPolelist, ParapetForm.ParapetData data, bool isEdit)
		{
			double height = data.Height;
			Transaction transaction = new Transaction(this.m_Doc, "Create parapet");
			Result result;
			try
			{
				transaction.Start();
				WallType wallType = null;
				try
				{
					if (data.CopingStyleIndex > 3)
					{
						wallType = this.CreateUserParapetWallType(data.TypeName, data.Thickness, data.Height, data.HasCoping, data.CopingStyleName);
					}
					else
					{
						wallType = this.CreateParapetWallType(data.TypeName, data.Thickness, data.Height, data.HasCoping, data.CopingStyleIndex);
					}
				}
				catch (Exception)
				{
                    if ((int)(int)transaction.GetStatus() == 1)
					{
						transaction.RollBack();
					}
					return Autodesk.Revit.UI.Result.Failed;
				}
				foreach (Pole2D pole2D in analyzedPolelist)
				{
					double num = 0.0;
					Level levelByElevation = this.GetLevelByElevation(pole2D.Elevation, ref num);
					try
					{
						Curve curve = pole2D.ReverseCenterCurve();
						if (pole2D.IsArcPole && pole2D.ComponentId != ElementId.InvalidElementId && Geometry.IsEqual((((this.m_Doc.GetElement(pole2D.ComponentId) as Wall).Location as LocationCurve).Curve as Arc).Normal, XYZ.BasisZ))
						{
							curve = pole2D.CenterCurve();
						}
						if (isEdit)
						{
							this.m_Doc.Delete(pole2D.ComponentId);
						}
						Wall wall = Wall.Create(this.m_Doc, curve, wallType.Id, levelByElevation.Id, height, num, false, false);
						wall.get_Parameter(BuiltInParameter.WALL_KEY_REF_PARAM).Set(2);
						ExtensibleStorageManager.WriteParapetExtensibleStorage(wall, data);
					}
					catch (Exception)
					{
					}
				}
				transaction.Commit();
				if (isEdit)
				{
					YJKMessageBox.Show("女儿墙编辑完成");
				}
				else
				{
					YJKMessageBox.Show("女儿墙创建完成");
				}
				result = Autodesk.Revit.UI.Result.Succeeded;
			}
			catch (Exception)
			{
				transaction.RollBack();
				result = Autodesk.Revit.UI.Result.Failed;
			}
			return result;
		}

		private Level GetLevelByElevation(double elevation, ref double offset)
		{
			List<Level> sortLevels = Common.GetSortLevels(this.m_Doc, double.MinValue, double.MaxValue);
			Level result = null;
			double num = double.MaxValue;
			foreach (Level level in sortLevels)
			{
				double num2 = elevation - level.Elevation;
				if (Geometry.LessThan(Math.Abs(num2), Math.Abs(num)))
				{
					result = level;
					num = num2;
				}
			}
			offset = num;
			return result;
		}

		private ExternalCommandData m_ComdData;

		private Document m_Doc;

        public static WindowHandle _hWndRevit;
	}
}
